<?php

Raise::load('core.RaiseObject');
Raise::load('core.collection.RaiseCollection');
Raise::load('core.reflection.RaiseVariable');
Raise::load('core.io.file.RaiseFileSystem');
Raise::load('core.io.file.RaiseFile');
Raise::load('core.ui.RaiseUIControl');
Raise::load('core.text.format.IRaiseFormatter');
Raise::load('core.text.regex.RaiseRegex');

/**
 * RaiseTemplate class
 * defines a template file where data can be set into the template
 *
 * @author Sam-Mauris Yong / hellclanner at live dot com
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package phpraise.core.ui
 * @since 1.2
 * @todo if conditional blocks
 */
class RaiseTemplate extends RaiseObject {

    const TEMPLATE_KEY_OPEN = '{';
    const TEMPLATE_KEY_CLOSE = '}';
    
    /**
     * Template fields IRaiseFormatter
     * @var RaiseCollection
     */
    private $fieldFormat;
    
    /**
     * Template fields and its corresponding values
     * @var RaiseCollection
     */
    private $fields;

    /**
     * The content of the template
     * @var string
     */
    private $template = '';

    /**
     * An array of known templates loaded by RaiseAppPackageLoader
     * @var array
     */
    private static $templates = array();

    /**
     * Creates a template file
     * @param string $t The template file or string to use
     */
    function __construct($t){
        $this->fields = new RaiseCollection();
        $this->fieldFormat = new RaiseCollection();
        $f = false;
        
        if(RaiseVariable::isType($t, RaiseVariable::TYPEOBJECT)){
            $t = (string)$t;
        }
        if(array_key_exists($t, self::$templates)){
            $f = self::$templates[$t];
        }
        if($f && RaiseFileSystem::fileExist($f)){
            $file = new RaiseFile($f);
            $this->template = $file->read();
        }else{
            $this->template = $t;
        }
    }

    /**
     * Get the collection of fields and their values that will be parsed into the template
     * @return RaiseCollection
     */
    public function fields(){
        return $this->fields;
    }

    /**
     * Get the collection of fields formatters
     * @return RaiseCollection
     */
    public function fieldFormat(){
        return $this->fieldFormat;
    }

    /**
     * Parses the template fields into the template and return the final result
     * @return string
     */
    public function parse(){
        $html = $this->template;
        foreach($this->fields as $k => $v){
            $key = self::TEMPLATE_KEY_OPEN . $k . self::TEMPLATE_KEY_CLOSE;
            if(strpos($html, $key) === false){
                continue;
            }else{
                if($this->fieldFormat->keyExists($k)){
                    $formatter = $this->fieldFormat->get($k);
                    if($formatter instanceof RaiseCollection){
                        foreach($formatter as $f){
                            if($f instanceof IRaiseFormatter){
                                $v = $f->parse($v);
                            }
                        }
                    }elseif($formatter instanceof IRaiseFormatter){
                        $v = $formatter->parse($v);
                    }
                }elseif($v instanceof RaiseTemplate){
                    $v = $v->parse();
                }elseif($v instanceof RaiseUIControl){
                    $v = $v->output();
                }elseif($v instanceof RaiseCollection){
                    $v = $v->join();
                }elseif(RaiseVariable::isType($v, RaiseVariable::TYPEOBJECT)){
                    $v = RaiseConvert::to(RaiseConvert::TO_STRING, $v);
                }elseif(RaiseVariable::isType($v, RaiseVariable::TYPEARRAY)){
                    $v = implode($v);
                }
                $html = str_replace($key, $v, $html);
            }
        }
        
        return $html;
    }

    /**
     * Add a template to RaiseTemplate's list of known templates
     * @param RaiseFile $template
     * @static
     */
    public static function loadTemplate($template){
        if($template instanceof RaiseFile){
            $name = $template->pathname();
            self::$templates[RaisePath::fileName($name)] = $name;
        }else{
            throw new RaiseInvalidArgumentException('RaiseTemplate::loadTemplate() - Argument $template expected to be RaiseFile object.');
        }
    }

    /**
     * Get the number of templates loaded in RaiseTemplate
     * @return integer
     * @static
     */
    public static function loadCount(){
        return count(self::$templates);
    }

    /**
     * Get the collection of tokens found in the template
     * @return RaiseCollection
     */
    public function tokens(){
        $tokens = new RaiseCollection();
        $i = preg_match_all('`' . RaiseRegex::escape(self::TEMPLATE_KEY_OPEN) . '([a-zA-Z0-9\.]+)' . RaiseRegex::escape(self::TEMPLATE_KEY_CLOSE) . '`is', $this->template, $matches, PREG_SET_ORDER);
        if($i > 0){
            foreach($matches as $m){
                $tokens->add($m[1]);
            }
        }
        return $tokens;
    }
    
    public function __toString() {
        $this->parse();
    }
}
